﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

//在线解析 http://www.aggsoft.com/ais-decoder.htm
//http://blog.csdn.net/happyparrot/article/details/1584079
//http://www.csdn123.com/html/exception/465/465332_465326_465331.htm
//http://wenku.baidu.com/view/0aba0a7e31b765ce050814b7.html ，AIS（自动识别系统）介绍
public class 数据信息
{
    public string 名称 { get; set; }
    public int 位数长度 { get; set; }

    public string 备注 { get; set; }

    public int 序号 { get; set; }
}
public partial class AIS数据解包 : System.Web.UI.Page
{
    string asistr = "!ABVDM,1,1,,B,169G?I0P007k`vT;BwhP7gv4@d0e,0*0A";
    protected void Page_Load(object sender, EventArgs e)
    {

        int xx = 215454000;
        var ccc = Convert.ToString(BitConverter.ToInt32(BitConverter.GetBytes(xx).Reverse().ToArray(), 0), 2);

        string 数据 = "169G?I0P007k`vT;BwhP7gv4@d0e";

        System.Collections.BitArray arr = new System.Collections.BitArray(数据.Select(p => (byte)p).ToArray());

        int cc = 0;
        for (int i = 0; i < arr.Count / 8; i++)
        {


            //取值位
            var a = GetVal<int>(arr, cc, cc + 8 - 1);
            Response.Write((char)a);
            cc = cc + 8;
        }
        Response.Write("<br/>");

        int num = 0;

        var bools = arr.Cast<bool>();

        Response.Write(string.Join("", bools.Select(p => p ? 1 : 0)));
        Response.Write("<br/>");


        //B类报文();
        //!AIVDM,1,1,,A,169E798P1n8fUMrAjLTDMgw<00Sb,0*77
        数据 = "169E798P1n8fUMrAjLTDMgw<00Sb";
        A类报文();
        foreach (var item in packegInfo.OrderBy(p => p.序号))
        {

            Response.Write(string.Join("", bools.Skip(num).Take(item.位数长度).Select(p => p ? 1 : 0)));

            var val = GetVal<long>(arr, num, num + item.位数长度 - 1);
            Response.Write("&");

            Response.Write("&");
            Response.Write(string.Format("{0}:{1}<br/>", item.名称, val));
            num = num + item.位数长度;
        }


    }

    void A类报文()
    {
        packegInfo.Add(new 数据信息() { 序号 = 1, 名称 = "	信息识别码	", 位数长度 = 6, 备注 = "	信息1、2、3的识别符	 " });
        packegInfo.Add(new 数据信息() { 序号 = 2, 名称 = "	重复次数指示	", 位数长度 = 2, 备注 = "	指示应该重发的次数。缺省为0，3表示不再重发	 " });
        packegInfo.Add(new 数据信息() { 序号 = 3, 名称 = "	用户识别码	", 位数长度 = 30, 备注 = "	MMSI号码	 " });
        packegInfo.Add(new 数据信息() { 序号 = 4, 名称 = "	航行状态	", 位数长度 = 4, 备注 = "	0=动力航行中；1=锚泊；2=未受令；3=机动性受限；4=受吃水限制；5=锚链系泊；6=搁浅；7=捕捞中；8=风帆动力航行；9~15为未来保留。	 " });
        packegInfo.Add(new 数据信息() { 序号 = 5, 名称 = "	转向率	", 位数长度 = 8, 备注 = "	0	 " });
        packegInfo.Add(new 数据信息() { 序号 = 6, 名称 = "	对地航速	", 位数长度 = 10, 备注 = "	以1/10节距为单位，1023=无；1022= 102.2节。	 " });
        packegInfo.Add(new 数据信息() { 序号 = 7, 名称 = "	船位精确度	", 位数长度 = 1, 备注 = "	1=高精度（差分式）；0= 低精度。	 " });
        packegInfo.Add(new 数据信息() { 序号 = 8, 名称 = "	经度	", 位数长度 = 28, 备注 = "	用1/10000分表示的经度（东= +，西= －）	 " });
        packegInfo.Add(new 数据信息() { 序号 = 9, 名称 = "	纬度	", 位数长度 = 27, 备注 = "	用1/10000分表示的纬度（北= +，南= －）	 " });
        packegInfo.Add(new 数据信息() { 序号 = 10, 名称 = "	对地航向	", 位数长度 = 12, 备注 = "	以1/10度表示的航向	 " });
        packegInfo.Add(new 数据信息() { 序号 = 11, 名称 = "	船首真航向	", 位数长度 = 9, 备注 = "	0	 " });
        packegInfo.Add(new 数据信息() { 序号 = 12, 名称 = "	时间标记	", 位数长度 = 6, 备注 = "	0	 " });
        packegInfo.Add(new 数据信息() { 序号 = 13, 名称 = "	Regional Application	", 位数长度 = 4, 备注 = "	0	 " });
        packegInfo.Add(new 数据信息() { 序号 = 14, 名称 = "	Spare	", 位数长度 = 1, 备注 = "	0	 " });
        packegInfo.Add(new 数据信息() { 序号 = 15, 名称 = "	RAIM Flag	", 位数长度 = 1, 备注 = "	0	 " });
        packegInfo.Add(new 数据信息() { 序号 = 16, 名称 = "	Communication state	", 位数长度 = 19, 备注 = "	0	 " });

    }

    void 末知类报文()
    {
        ///末知类报文
        packegInfo.Add(new 数据信息() { 序号 = 1, 名称 = "信息识别码", 位数长度 = 6, 备注 = "信息1、2、3的识别符" });
        packegInfo.Add(new 数据信息() { 序号 = 2, 名称 = "数据终端设备", 位数长度 = 1, 备注 = "数据终端准备状态（0=可用；1=不可用）" });
        packegInfo.Add(new 数据信息() { 序号 = 3, 名称 = "数据显示符", 位数长度 = 1, 备注 = "可发数据（0=无；1=有）" });
        packegInfo.Add(new 数据信息() { 序号 = 4, 名称 = "用户识别码", 位数长度 = 30, 备注 = "MMSI号码" });
        packegInfo.Add(new 数据信息() { 序号 = 5, 名称 = "航行状态", 位数长度 = 42, 备注 = "0=动力航行中；1=锚泊；2=未受令；3=机动性受限；4=受吃水限制；5=锚链系泊；6=搁浅；7=捕捞中；8=风帆动力航行；9~15为未来保留" });
        packegInfo.Add(new 数据信息() { 序号 = 6, 名称 = "转向率", 位数长度 = 8, 备注 = "以ROT(AIS)=4.733SQRT(ROT(IND))度/分钟编码，ROTIND为转向率（720度/分钟），以外部传感器显示。" });
        packegInfo.Add(new 数据信息() { 序号 = 7, 名称 = "对地航速", 位数长度 = 10, 备注 = "以1/10节距为单位，1023=无；1022=102.2节" });
        packegInfo.Add(new 数据信息() { 序号 = 8, 名称 = "船位精确度", 位数长度 = 1, 备注 = "1=高精度（差分式）；0=低精度。" });
        packegInfo.Add(new 数据信息() { 序号 = 9, 名称 = "经度", 位数长度 = 28, 备注 = "在1/10000分钟内的经度（180°，东=+，西=－）" });
        packegInfo.Add(new 数据信息() { 序号 = 10, 名称 = "纬度", 位数长度 = 27, 备注 = "在1/10000分钟内的纬度（90°，北=+，南=－）" });
        packegInfo.Add(new 数据信息() { 序号 = 11, 名称 = "COG", 位数长度 = 12, 备注 = "在1/103时对地航线（03599" });
        packegInfo.Add(new 数据信息() { 序号 = 12, 名称 = "航向", 位数长度 = 9, 备注 = "度数(0－359)(511表示无效)" });
        packegInfo.Add(new 数据信息() { 序号 = 13, 名称 = "时间标记", 位数长度 = 6, 备注 = "当报告时UTC秒(0－59)，或63当定位系统未运行" });
        packegInfo.Add(new 数据信息() { 序号 = 14, 名称 = "备用", 位数长度 = 9, 备注 = "" });
        packegInfo.Add(new 数据信息() { 序号 = 15, 名称 = "通讯状态", 位数长度 = 18, 备注 = "" });

    }

    void B类报文()
    {
        ///末知类报文
        packegInfo.Add(new 数据信息() { 序号 = 1, 名称 = "信息识别码", 位数长度 = 6, 备注 = "信息1、2、3的识别符" });
        packegInfo.Add(new 数据信息() { 序号 = 2, 名称 = "数据终端设备", 位数长度 = 1, 备注 = "数据终端准备状态（0=可用；1=不可用）" });
        packegInfo.Add(new 数据信息() { 序号 = 3, 名称 = "数据显示符", 位数长度 = 1, 备注 = "可发数据（0=无；1=有）" });
        packegInfo.Add(new 数据信息() { 序号 = 4, 名称 = "用户识别码", 位数长度 = 30, 备注 = "MMSI号码" });
        packegInfo.Add(new 数据信息() { 序号 = 5, 名称 = "纬度", 位数长度 = 27, 备注 = "在1/10000分钟内的纬度（90°，北=+，南=－）" });
        packegInfo.Add(new 数据信息() { 序号 = 6, 名称 = "经度", 位数长度 = 28, 备注 = "在1/10000分钟内的经度（180°，东=+，西=－）" });

        packegInfo.Add(new 数据信息() { 序号 = 7, 名称 = "时间", 位数长度 = 6, 备注 = "在1/103时对地航线（03599" });
        packegInfo.Add(new 数据信息() { 序号 = 8, 名称 = "对地航速", 位数长度 = 11, 备注 = "在1/103时对地航线（03599" });
        packegInfo.Add(new 数据信息() { 序号 = 9, 名称 = "对地航向", 位数长度 = 12, 备注 = "在1/103时对地航线（03599" });

        packegInfo.Add(new 数据信息() { 序号 = 10, 名称 = "船首方位", 位数长度 = 9, 备注 = "度数(0－359)(511表示无效)" });

        packegInfo.Add(new 数据信息() { 序号 = 11, 名称 = "航行状态", 位数长度 = 2, 备注 = "0=动力航行中；1=锚泊；2=未受令；3=机动性受限；4=受吃水限制；5=锚链系泊；6=搁浅；7=捕捞中；8=风帆动力航行；9~15为未来保留" });
        packegInfo.Add(new 数据信息() { 序号 = 12, 名称 = "转向率", 位数长度 = 8, 备注 = "以ROT(AIS)=4.733SQRT(ROT(IND))度/分钟编码，ROTIND为转向率（720度/分钟），以外部传感器显示。" });
        packegInfo.Add(new 数据信息() { 序号 = 13, 名称 = "备用", 位数长度 = 9, 备注 = "" });
        packegInfo.Add(new 数据信息() { 序号 = 14, 名称 = "通讯状态", 位数长度 = 18, 备注 = "" });

    }


    public List<数据信息> packegInfo = new List<数据信息>();




    /// <summary>
    /// 取指定位置的数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="arr"></param>
    /// <param name="start">0开始</param>
    /// <param name="end"></param>
    /// <returns></returns>
    public T? GetVal<T>(System.Collections.BitArray arr, int start, int end)
        where T : struct
    {


        long result = 0;
        int n = 0;
        for (int k = start; k <= end; k++)
        {

            long s = 0;
            if (arr[k])
            {
                s = 1;
                //Response.Write(1);
            }
            else
            {
                // Response.Write(0);
            }
            result = result | (s << n);
            n++;
        }
        dynamic cc = result;

        return new Nullable<T>((T)cc);





        //return null;


    }

}